import {
  _decorator,
  Component,
  EventTouch,
  Input,
  input,
  instantiate,
  Prefab,
  UITransform,
  Node,
  Vec3,
  view,
  Collider2D,
  Contact2DType,
  IPhysics2DContact,
  Animation,
  Enum,
  Sprite,
  AudioClip,
} from "cc";
import { SetBasicInfo } from "../Utils/SetBasicInfo";
import { Reward, RewardType } from "./Reward";
import { GameManager } from "./GameManager";
import { LifeCountUI } from "./UI/LifeCountUI";
import { AudioMgr } from "./AudioMgr";
const { ccclass, property } = _decorator;

// 子弹数量枚举
enum ShootType {
  OneShoot,
  TwoShoot,
}

@ccclass("Player")
export class Player extends Component {
  // 屏幕宽高
  pageWidth: number = 0;
  pageHeight: number = 0;

  // 子弹发射间隔
  @property
  shootRate: number = 0.5;

  // 场景
  @property(Node)
  bulletParent: Node = null;

  // 子弹空节点（存放子弹）
  @property(Prefab)
  bullet1Prefab: Prefab = null;

  // 子弹1发射位置
  @property(Node)
  position1: Node = null;

  // 子弹发射类型，默认单发
  @property({ type: Enum(ShootType), displayName: "子弹发射类型" })
  shootType: ShootType = ShootType.TwoShoot;

  // 子弹空节点（存放子弹）
  @property(Prefab)
  bullet2Prefab: Prefab = null;

  // 子弹2发射位置
  @property(Node)
  position2: Node = null;

  // 子弹3发射位置
  @property(Node)
  position3: Node = null;

  // 血量
  @property
  lifeCount: number = 3;

  // 动画
  @property(Animation)
  anim: Animation = null;

  // 受伤动画
  @property
  animHit: string = "";

  // 死亡动画
  @property
  animDown: string = "";

  // 无敌时间
  @property
  invincibleTime: number = 1;

  // 无敌计时器
  invincibleTimer: number = 0;
  isInvincible: boolean = false;

  // 双发奖励时间
  @property
  twoShootTime: number = 5;

  // 双发子弹计时器
  twoShootTimer: number = 0;

  lastReward: Reward = null;

  // 子弹发射间隔
  shootTimer: number = 0;
  collider: Collider2D = null;

  @property(LifeCountUI)
  lifeCountUI: LifeCountUI = null;

  @property(AudioClip)
  bulletAudio: AudioClip = null;

  @property(AudioClip)
  getBombAudio: AudioClip = null;

  @property(AudioClip)
  getDoubleAudio: AudioClip = null;

  // 是否可以被控制
  private canControl: boolean = true;

  protected start(): void {
    this.getBgHeight();
    this.lifeCountUI.onLifeChange(this.lifeCount);
  }

  protected onLoad(): void {
    input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
    const collider = this.getComponent(Collider2D);
    this.collider = collider;
    this.collider?.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
  }

  protected onDestroy(): void {
    input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
    this.collider?.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
  }

  /**
   * 获取背景高度
   */
  getBgHeight() {
    const { width, height } = view.getVisibleSize();
    this.pageWidth = width;
    this.pageHeight = height;
  }

  onBeginContact(_selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
    const reward = otherCollider.getComponent(Reward);
    // 守卫代码
    // 如果不是奖励物品
    if (!reward) return this.onContactToEnemy();
    // 走到这里说明碰到了奖励物品
    this.onContactToReward(reward);
  }

  // 切换双发
  transitionToTwoShoot() {
    this.shootType = ShootType.TwoShoot;
    this.twoShootTimer = 0;
    this.anim.play("twoShoot");
  }

  // 切换单发
  transitionToOneShoot() {
    this.shootType = ShootType.OneShoot;
    this.anim.play("oneShoot");
  }

  // 接触到奖励物品
  onContactToReward(reward: Reward) {
    // 如果实例相同，说明触发过了
    if (reward === this.lastReward) return;
    this.lastReward = reward;
    switch (reward.rewardType) {
      // 双发
      case RewardType.TwoShoot:
        AudioMgr.inst.playOneShot(this.getDoubleAudio);
        this.transitionToTwoShoot();
        break;
      // 炸弹
      case RewardType.Bomb:
        AudioMgr.inst.playOneShot(this.getBombAudio);
        GameManager.getInstance().AddBomb();
        break;
    }

    // 将碰撞器禁用，让它不在与其他物体发生碰撞
    reward.getComponent(Collider2D).enabled = false;
    // 将奖励物品隐藏
    reward.getComponent(Sprite).enabled = false;
  }

  /**
   * 与敌人发生接触的时候
   */
  onContactToEnemy() {
    if (this.isInvincible) return;
    this.isInvincible = true;
    this.changeLifeCount(-1);
    // 敌人未死亡时运行hit动画，死亡时播放down动画
    if (this.lifeCount > 0) {
      this.anim.play(this.animHit);
    } else {
      this.anim.play(this.animDown);
    }

    if (this.lifeCount <= 0) {
      // 当前角色死亡
      this.shootType = ShootType.OneShoot;
      // 禁用碰撞
      this.collider && (this.collider.enabled = false);
      // 等待动画播放完
      this.scheduleOnce(() => {
        GameManager.getInstance().gameOver();
      }, 0.4);
    }
  }

  /**
   * 更新lifeCount
   */
  changeLifeCount(count: number) {
    this.lifeCount += count;
    this.lifeCountUI.onLifeChange(this.lifeCount);
  }

  /**
   * 触摸移动
   * @param event 事件对象 {@link EventTouch}
   */
  onTouchMove(event: EventTouch) {
    // 如果游戏暂停
    if (!this.canControl) return;

    // 如果血量小于1 不继续执行
    if (this.lifeCount < 1) return;
    const p = this.node.position;
    // 计算移动后的位置 模型位置 + 移动距离
    const moveX = p.x + event.getDeltaX();
    const moveY = p.y + event.getDeltaY();
    // 计算移动后的位置
    let targetPosition = new Vec3(moveX, moveY, p.z);
    // 获取模型的尺寸 Player
    const { width: modelWidth, height: modelHeight } = this.node.getComponent(UITransform).contentSize;
    // 屏幕的宽度一半 - 模型的十分之一 = 最佳边界位置
    const halfWidth = this.pageWidth / 2 - modelWidth / 10;
    // 屏幕的高度一半 - 模型的高度 = 模型到达屏幕底部的位置
    const halfHeight = this.pageHeight / 2 - modelHeight;

    // 边界处理
    if (targetPosition.x < -halfWidth || moveX > halfWidth) return;
    if (targetPosition.y > halfHeight || moveY < -((this.pageHeight - modelHeight) / 2)) return;

    SetBasicInfo.setPosition(this.node, targetPosition);
  }

  protected update(dt: number): void {
    switch (this.shootType) {
      case ShootType.OneShoot:
        this.oneShoot(dt);
        break;
      case ShootType.TwoShoot:
        this.twoShoot(dt);
        break;
    }

    if (this.isInvincible) {
      this.invincibleTimer += dt;
      if (this.invincibleTimer >= this.invincibleTime) {
        this.isInvincible = false;
        this.invincibleTimer = 0;
      }
    }
  }

  // 处理单发
  oneShoot(dt: number) {
    // 初始时间+=dt
    this.shootTimer += dt;
    // 如果时间大于子弹发射间隔
    if (this.shootTimer >= this.shootRate) {
      AudioMgr.inst.playOneShot(this.bulletAudio, 0.1);
      this.shootTimer = 0;
      // 发射子弹 克隆已有节点
      const bullet1 = instantiate(this.bullet1Prefab);
      // 添加到场景中
      this.bulletParent.addChild(bullet1);
      // 设置子弹位置（世界坐标）
      bullet1.setWorldPosition(this.position1.worldPosition);
    }
  }

  // 处理双发
  twoShoot(dt: number) {
    // 双发子弹
    this.twoShootTimer += dt;
    if (this.twoShootTimer >= this.twoShootTime) {
      this.transitionToOneShoot();
    }
    // 初始时间+=dt
    this.shootTimer += dt;
    // 如果时间大于子弹发射间隔
    if (this.shootTimer >= this.shootRate) {
      AudioMgr.inst.playOneShot(this.bulletAudio, 0.1);
      this.shootTimer = 0;
      // 发射子弹 克隆已有节点
      const bullet1 = instantiate(this.bullet2Prefab);
      const bullet2 = instantiate(this.bullet2Prefab);
      // 添加到场景中
      this.bulletParent.addChild(bullet1);
      this.bulletParent.addChild(bullet2);
      // 设置子弹位置（世界坐标）
      bullet1.setWorldPosition(this.position2.worldPosition);
      bullet2.setWorldPosition(this.position3.worldPosition);
    }
  }

  disableControl(flag: boolean) {
    this.canControl = flag;
  }
}
